program LbmpScktClient;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, uDZSysUtils, uDZPersistent, uDZWinsock2, uDZSocketUtils, uDZSocket,
  uDZMD5, uDZCRC, DLMD5, uDZSHA, uDZXML, uLBMPPackage in '..\common\uLBMPPackage.pas';

var
  ServerIP: string;
  ServerPort: Integer;
  Socket: TDzClientSocket;

procedure SendRequest(Connection: TDzClientSocket; Request: TRequestPackage);
var
  Hdr: TLbmpPkgHdr;
  Stream: TMemoryStream;
begin
  Hdr.Signature := 'lbmp';
  Hdr.HdrLen := SizeOf(Hdr);
  Hdr.Format := Ord(afBinary);
  Hdr.ReqType := Ord(Request.ReqType);
  Hdr.Option := 0;
  Hdr.DataLen := 0;
  Stream := TMemoryStream.Create;
  try
    Stream.Size := 1024;
    Stream.Seek(SizeOf(Hdr), soFromBeginning);
    Request.SaveToStream(Stream);
    Hdr.DataLen := Stream.Position - SizeOf(Hdr);
    Stream.Seek(0, soFromBeginning);
    Move(Hdr, Stream.Memory^, SizeOf(Hdr));
    Connection.Send(Stream.Memory^, Hdr.HdrLen + Hdr.DataLen);
  finally
    Stream.Free;
  end;
end;

procedure CopyResponse(Response: TResponsePackage);
var
  Resp: TResponsePackage;
begin
  Resp := TResponseClass(Response.ClassType).Create;
  try
    Resp.AsXML := Response.AsXML;
    Writeln(Resp.AsXML);
  finally
    Resp.Free;
  end;
end;

procedure DoRequest(ReqType: TRequestType; Phones: TStrings);
var
  Request: TRequestPackage;
  Response: TResponsePackage;
  Hdr: TLbmpPkgHdr;
  ms: TMemoryStream;
begin
  Request := RequestClasses[ReqType].Create;
  if ReqType in [rtGetState..rtCoordLoc] then
    TREQMultiPhone(Request).Phones.Assign(Phones);
  try
    try
      if not Socket.Connected then Socket.Connect(ServerIP, ServerPort);
      SendRequest(Socket, Request);
      Socket.Read(Hdr, SizeOf(Hdr), nil, MSG_WAITALL);
      ms := TMemoryStream.Create;
      Response := ResponseClasses[ReqType].Create;
      try
        ms.Size := Hdr.DataLen;
        Socket.Read(ms.Memory^, ms.Size, nil, MSG_WAITALL);
        ms.Position := 0;
        Response.LoadFromStream(ms, TDzArchiveFormat(Hdr.Format));
        Writeln(Response.AsXML);
      finally
        ms.Free;
        Response.Free;
      end;
    except
      on E: Exception do
      begin
        if E is EDzSocketException then
        begin
          Writeln(E.Classname, ': ', E.Message);
          Socket.Close;
        end;
      end;
    end;
  finally
    Request.Free;
  end;
end;

function DLMD5S(const Input: AnsiString): AnsiString;
var
  Digest: TDLMD5Digest;
begin
  DLMD5.MD5To(Pointer(Input), Length(Input), @Digest);
  Result := MemHex(Digest, SizeOf(Digest));
end;

function FileMD5(const FileName: string): AnsiString;
var
  Digest: TMD5Digest;
begin
  MD5File(FileName, Digest);
  Result := MemHex(Digest, SizeOf(Digest));
end;

procedure MD5Test;
begin
  Writeln(MD5String('abcd'));
  Writeln(DLMD5S('abcd'));
  Writeln(MD5String('zhouzuoji'));
  Writeln(DLMD5S('zhouzuoji'));
  Writeln(FileMD5('D:\My Documents\Downloads\WejoinMessenger\Source\Common\md5.pas'));
  Writeln(CRC32File('D:\My Documents\Downloads\WejoinMessenger\Source\Common\md5.pas'));
end;

var
  Str, Cmd: string;
  i, j: Integer;
  ReqType: TRequestType;
  Phones: TStrings;
begin
  Socket := TDzClientSocket.Create;
  Phones := TStringList.Create;
  try
    try
      Write('input server ip(default 127.0.0.1):');
      Readln(ServerIP);
      if ServerIP = '' then ServerIP := '127.0.0.1';
      Write('input server port(default 8080):');
      try
        Readln(ServerPort);
      except
        ServerPort := 8080;
      end;
      if ServerPort = 0 then ServerPort := 8080;
      while True do
      begin
        Write('input command:');
        Readln(Str);
        i := 1;
        while (i <= Length(Str)) and (Str[i] <> #32) do Inc(i);
        Cmd := Copy(Str, 1, i - 1);
        if SameText(Cmd, 'exit') then Exit;
        if SameText(Cmd, 'GetState') then ReqType := rtGetState
        else if SameText(Cmd, 'Reg') then ReqType := rtReg
        else if SameText(Cmd, 'AgreeReg') then ReqType := rtAgreeReg
        else if SameText(Cmd, 'Unreg') then ReqType := rtUnreg
        else if SameText(Cmd, 'CityLoc') then ReqType := rtCityLoc
        else if SameText(Cmd, 'CoordLoc') then ReqType := rtCoordLoc
        else if SameText(Cmd, 'ServerInfo') then ReqType := rtServerInfo
        else begin
          Writeln('invalid command');
          Continue;
        end;
        if ReqType in [rtGetState..rtCoordLoc] then
        begin
          Phones.Clear;
          while i <= Length(Str) do
          begin
            while (i <= Length(Str)) and (Str[i] = #32) do Inc(i);
            if i <= Length(Str) then
            begin
              j := i + 1;
              while (j <= Length(Str)) and (Str[j] <> #32) do Inc(j);
              Phones.Add(Copy(Str, i, j - i));
              i := j + 1;
            end;
          end;
          if Phones.Count = 0 then
          begin
            Writeln('invalid command');
            Continue;
          end;
        end;
        DoRequest(ReqType, Phones);
      end;
    except
      on E:Exception do
        Writeln(E.Classname, ': ', E.Message);
    end;
  finally
    Socket.Free;
    Phones.Free;
  end;
end.
